package pacs.sgc.dao;

import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import pacs.sgc.classesbasicas.ContaPagar;
import pacs.sgc.classesbasicas.ContaReceber;
import pacs.sgc.exceptions.AcessoAoBancoException;
import pacs.sgc.exceptions.ConexaoComBancoException;

public class ContaReceberDao implements IContaReceberDao {
	
	private Conexao conexao;
	private PreparedStatement statement = null;
	private ResultSet rs = null;
	
	private final String SQL_INSERT = "INSERT INTO contareceber(codigo, numero, data, vencimento, cedente, sacado, instrucoes, valorTotal, paga) " +
		"VALUES(?,?,?,?,?,?,?,?,?)"; //9 parametros	
	private final String SQL_DELETE = "DELETE FROM contareceber WHERE numero = ?";
	private final String SQL_UPDATE = "UPDATE contareceber SET numero = ?, data = ?, vencimento = ?, cedente = ?, sacado = ?, " +
		"instrucoes = ?, valorTotal = ?, paga = ? WHERE codigo = ?";
	private final String SQL_SELECT = "SELECT codigo, numero, data, vencimento, cedente, sacado, instrucoes, valorTotal, paga FROM contareceber WHERE numero = ? OR data = ?";
	private final String SQL_SELECT_CODIGO = "SELECT codigo, numero, data, vencimento, cedente, sacado, instrucoes, valorTotal, paga FROM contareceber WHERE codigo = ?";
	private final String SQL_SELECT_TODOS = "SELECT codigo, numero, data, vencimento, cedente, sacado, instrucoes, valorTotal, paga FROM contareceber";
	private final String SQL_SELECT_ULTIMO = "SELECT codigo FROM contareceber WHERE codigo = (SELECT MAX(codigo) FROM contareceber)";

	/**
	 * Construtor Default.
	 *
	 */
	public ContaReceberDao(){
		this.conexao = FabricaConexao.criarConexao();
	}
	
	public ContaReceberDao(Conexao conexao){
		this.conexao = conexao;
	}
	
	
	/**
	 * Metodo que atualiza uma conta a receber existente
	 * 
	 * @param atualizada
	 * @return void
	 * @throws ConexaoComBancoException
	 * @throws AcessoAoBancoException
	 */
	public void atualizar(ContaReceber atualizada)
			throws ConexaoComBancoException, AcessoAoBancoException {
		PreparedStatement update = null;
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT_CODIGO);
			this.statement.setInt(1,atualizada.getCodigo());
			this.rs = statement.executeQuery();
			
			if(rs.next()){
				update = this.conexao.getCon().prepareStatement(this.SQL_UPDATE);
				
				update.setString(1, atualizada.getNumero());
				update.setDate(2, atualizada.getData());
				update.setDate(3, atualizada.getVencimento());
				update.setString(4, atualizada.getCedente());
				update.setString(5, atualizada.getSacado());				
				update.setString(6, atualizada.getInstrucoes());
				update.setDouble(7, atualizada.getValorTotal());
				update.setBoolean(8, atualizada.isPaga());
				update.setInt(9, atualizada.getCodigo());
				
				update.execute();
				update.close();				
			}
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
				
				if(update != null)
					update.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}	
	}

	
	/**
	 * Metodo que pega do banco o ultimo codigo inserido na tabela contareceber e 
	 * gera o proximo codigo a ser inserido
	 * 
	 * @return int;
	 * @throws AcessoAoBancoException
	 * @throws ConexaoComBancoException
	 */
	public int gerarCodigo() throws ConexaoComBancoException,
			AcessoAoBancoException {
		// TODO Auto-generated method stub
		int proximoCodigo = 1;
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT_ULTIMO);
			
			this.rs = statement.executeQuery();
			
			if(this.rs.next())
				proximoCodigo = rs.getInt("codigo") + 1;
			
		} catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
		return proximoCodigo;
	}
	

	/**
	 * Metodo que insere um novo registro na tabela contareceber.
	 * 
	 * @param novaContaReceber
	 * @return void
	 * @throws AcessoAoBancoException
	 * @throws ConexaoComBancoException
	 */
	public void inserir(ContaReceber novaContaReceber)
			throws ConexaoComBancoException, AcessoAoBancoException {
		try{
			this.conexao.abrirConexao();
			
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_INSERT);
			this.statement.setInt(1, novaContaReceber.getCodigo());
			this.statement.setString(2, novaContaReceber.getNumero());
			this.statement.setDate(3, novaContaReceber.getData());
			this.statement.setDate(4, novaContaReceber.getVencimento());
			this.statement.setString(5, novaContaReceber.getCedente());
			this.statement.setString(6, novaContaReceber.getSacado());			
			this.statement.setString(7, novaContaReceber.getInstrucoes());
			this.statement.setDouble(8, novaContaReceber.getValorTotal());
			this.statement.setBoolean(9, novaContaReceber.isPaga());			
			
			this.statement.execute();
		} catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{
			try{
				if(this.conexao != null)
					this.conexao.fecharConexao();
				if(this.statement != null)
					this.statement.close();	
			}catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
	}

	
	/**
	 * Metodo que lista todos os contas a receber cadastradas
	 * 
	 * @return List<ContaReceber>
	 * @throws AcessoAoBancoException 
	 * @throws ConexaoComBancoException 
	 */
	public List<ContaReceber> listar() throws ConexaoComBancoException,
			AcessoAoBancoException {
		// TODO Auto-generated method stub
		List<ContaReceber> listaDeContas = new ArrayList<ContaReceber>();
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT_TODOS);			
			this.rs = this.statement.executeQuery();
			
			while(rs.next()){
				int codigo = this.rs.getInt(1);
				String numero = this.rs.getString(2);
				Date data = this.rs.getDate(3);
				Date vencimento = this.rs.getDate(4);
				String cedente = this.rs.getString(5);				
				String sacado = this.rs.getString(6);				
				String instrucoes = this.rs.getString(7);
				double valorTotal = this.rs.getDouble(8);
				boolean paga = this.rs.getBoolean(9);
				
				listaDeContas.add(new ContaReceber(codigo, numero, data, vencimento, cedente, sacado, instrucoes, valorTotal, paga));
			}
			
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
		return listaDeContas;
	}
	


	/**
	 * Metodod que localiza contas a receber a partir de seu numero ou sua data.
	 * 
	 * @param numero
	 * @param data
	 * @return List<ContaReceber>
	 * @throws AcessoAoBancoException 
	 * @throws ConexaoComBancoException
	 */
	public List<ContaReceber> localizar(String numero, Date data)
			throws ConexaoComBancoException, AcessoAoBancoException {
		// TODO Auto-generated method stub
		List<ContaReceber> listaDeContas = new ArrayList<ContaReceber>();
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT);
			this.statement.setString(1, numero);
			this.statement.setDate(2, data);
			this.rs = this.statement.executeQuery();
			
			while(rs.next()){
				int codigo = this.rs.getInt(1);
				String numero2 = this.rs.getString(2);
				Date data2 = this.rs.getDate(3);
				Date vencimento = this.rs.getDate(4);
				String cedente = this.rs.getString(5);				
				String sacado = this.rs.getString(6);				
				String instrucoes = this.rs.getString(7);
				double valorTotal = this.rs.getDouble(8);
				boolean paga = this.rs.getBoolean(9);
				
				listaDeContas.add(new ContaReceber(codigo, numero2, data2, vencimento, cedente, sacado, instrucoes, valorTotal, paga));
			}
			
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
		return listaDeContas;
	}

	
	/**
	 * Metodo que remove um registro da tabela contareceber que tenha o numero igual ao numero passado.
	 * 
	 * @param numero
	 * @return void
	 * @throws AcessoAoBancoException
	 * @throws ConexaoComBancoException
	 */
	public void remover(String numero) throws ConexaoComBancoException,
			AcessoAoBancoException {
		try{
			this.conexao.abrirConexao();
			
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_DELETE);
			this.statement.setString(1, numero);
			this.statement.execute();
			
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{
			try{
				if(this.conexao != null)
					this.conexao.fecharConexao();
				if(this.statement != null)
					this.statement.close();	
			}catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}

	}

}
